package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import som.Board;
import som.Cell;

/**
 * Class manages the GUI display of the SOM
 */
public class GuiManager {
		
	private static final String WINDOW_NAME = "SOM"; // title for the display window
	private static final int BOARD_SIZE = 6; // grid size	
	private static final int NUM_CLASSES = 11; // 10 digits + no-assigned-samples
	private static final int FRAME_SIZE = 350;
	private static final int X_FRAME_BOUND = 100; 
	private static final int Y_FRAME_BOUND = 100;
	private static final int WIDTH_FRAME_BOUND = 450;
	private static final int HEIGHT_FRAME_BOUND = 300;		

	private Board resultBoard; // resulting cells data
	private JFrame frame; // frame for the entire display
	private JButton[][] buttons; // holds a button for each cell
	
	/**
	 * Constructor- creates an object to manage the GUI display
	 * @param resultBoard SOM to be displayed
	 */
	public GuiManager(Board resultBoard) {
		
		// set cells data
		this.resultBoard = resultBoard;
		
		// initialize display objects
		initDisplay();
	}		

	/**
	 * Allocates the GUI objects and colors each cell
	 * according to the most prominent classification
	 * among its assigned samples
	 */
	private void initDisplay() {

		// create a new frame
		frame = new JFrame(WINDOW_NAME);
		frame.setBounds(X_FRAME_BOUND, Y_FRAME_BOUND, WIDTH_FRAME_BOUND, HEIGHT_FRAME_BOUND);
		frame.setSize(FRAME_SIZE, FRAME_SIZE);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		frame.setLocationByPlatform(true);
		
		// disable window resize while running
		frame.setResizable(false);
		
		// set layout for the board buttons
		BorderLayout borderLayout = new BorderLayout();
		frame.getContentPane().setLayout(borderLayout);		
		JPanel boardPanel = new JPanel();
		frame.getContentPane().add(boardPanel, BorderLayout.CENTER);
		
		// create grid on which buttons will be placed
		GridLayout buttonsGrid = new GridLayout(BOARD_SIZE, BOARD_SIZE);
		boardPanel.setLayout(buttonsGrid);
		
		// allocate a matrix to hold all board buttons
		buttons = new JButton[BOARD_SIZE][BOARD_SIZE];
		
		// add board buttons
		for (int row = 0; row < BOARD_SIZE; ++row) {
			for (int col = 0; col < BOARD_SIZE; ++col) {
		
				// create a new button on the board
				JButton btn = new JButton();
				buttons[row][col] = btn;
	
				// set background according to its matching cell's value
				btn.setBackground(getColor(row, col));
				btn.setBorderPainted(false);

				// place the button on the board
				boardPanel.add(btn);
			}			
		}
		
		// create legend to map each color to its number (a.k.a classification)
		GridLayout classesGrid = new GridLayout(NUM_CLASSES, 1);
		JPanel classesPanel = new JPanel();
		classesPanel.setLayout(classesGrid);
		frame.getContentPane().add(classesPanel, BorderLayout.WEST);
		for (int i = 0 ; i < NUM_CLASSES-1 ; ++i) {
			
			// create a new button
			JButton btn = new JButton("" + i);

			// set background according to current classification
			btn.setBackground(getColor(i));
			
			btn.setBorderPainted(false);
			
			// place the button on the board
			classesPanel.add(btn);
		}
		
		// add bar indicating a cell with no assigned samples
		JButton btn = new JButton("none");
		// set background according to current classification
		btn.setBackground(getColor(Cell.ERROR_VALUE));
		
		btn.setBorderPainted(false);
		
		// place the button on the board
		classesPanel.add(btn);
	}
	
	/**
	 * Calculates the color matching cell at given position.
	 * The color is based on the most prominent classification
	 * among the cell's assigned samples
	 * @param row cell's row index
	 * @param col cell's column index
	 * @return color matching cell at indicated position
	 */
	private Color getColor(int row, int col) {
		
		// get cell's most prominent classification
		double prominent = resultBoard.getCell(row, col).getMostProminentClassification();
		
		// return matching color
		return getColor((float) prominent);
	}
	
	/**
	 * Returns a color matching given classification:
	 * returns a color in HSV representation, where Saturation and Value are fixed,
	 * but Hue is set according to sample's classification 
	 * @param classification classification value
	 * @return color matching given classification
	 */
	private Color getColor(float classification) {
		
		// handle case of no samples are classified to this cell
		if (classification == Cell.ERROR_VALUE) {			
			return Color.getHSBColor(0.0f, 0.0f, 0.0f);
		}
		
		// calculate relative color (Hue value in HSV representation)
		return Color.getHSBColor(classification / 10.0f, 0.9f, 0.9f);
	}
		
	/**
	 * Displays the SOM
	 */
	public void display() {
		frame.setVisible(true);
	}
}
